<script lang="ts" setup>
import { apiMenu } from "@/api/sys";
import { useMessage } from "@/hooks/web/use-message";
import { MenuType, type MenuInfo, type AdvancedSearch } from "@/models";
import type { ElTree } from "element-plus";
import { reactive, ref } from "vue";
import { type VxeModalInstance, type VxeModalProps } from "vxe-table";

//#region [state]
type PageState = { show: boolean; children: number[]; exclude: number[]; tree: MenuInfo[]; isFunctions: boolean; pid?: number };
const page = reactive<PageState>({ show: false, children: [], exclude: [], tree: [], isFunctions: false });
const emit = defineEmits<{ (event: "onsaved", value?: Nullable<number>): void }>();
const treeRef = ref<InstanceType<typeof ElTree>>();
const { 页面, 功能, 信息 } = MenuType;
const { createMessage } = useMessage();
//#endregion

//#region [modal]
const modalRef = ref<VxeModalInstance>();
const modalOptions = reactive<VxeModalProps>({
  title: "选择父级菜单",
  resize: true,
  destroyOnClose: true,
  escClosable: true,
  showFooter: true,
  width: 900,
  height: 500,
  position: { top: window.innerHeight * 0.2 },
});
//#endregion

//#region [action]
function open(children: MenuInfo[], checked: MenuInfo[]) {
  page.isFunctions = children.every((c) => c.type === 功能);
  if (!page.isFunctions && children.some((c) => c.type === 功能)) {
    createMessage("warning", "功能类型菜单不能和其它类型的菜单分配至同一父级！");
    return;
  }
  page.children = children.map((c) => c.id);
  page.exclude = checked.map((c) => c.id);
  page.show = true;
  load();
}
async function load() {
  const search: AdvancedSearch<MenuInfo> = { s: [{ f: "sortId", s: "ASC" }] };
  const response = await apiMenu.find<MenuInfo>(search);
  if (!response.value) return;

  const menus: MenuInfo[] = Array.from(response.value);
  for (const menu of menus) {
    let parent = menus.find((p) => p.id === menu.pid);
    if (!parent) continue;

    if (menu.type === 功能) {
      if (!parent.actions) parent.actions = [];
      parent.actions.push(menu);
    } else {
      if (!parent.children) parent.children = [];
      parent.children.push(menu);
    }
  }

  page.tree = menus.filter((r) => r.pid === null || r.pid === undefined);
}
function isExclude(menu: MenuInfo) {
  return page.exclude.indexOf(menu.id) > -1 || (!page.isFunctions && menu.type === 页面) || (page.isFunctions && menu.type !== 页面) || menu.type === 信息;
}
async function save() {
  if (page.pid && page.children.length > 0) {
    const response = await apiMenu.changeParent(page.pid, page.children);
    if (response.value) {
      emit("onsaved");
      page.show = false;
    }
  }
}
function close() {
  page.pid = undefined;
  page.show = false;
}
//#endregion

defineExpose({ open });
</script>

<template>
  <vxe-modal ref="modalRef" v-model="page.show" :="modalOptions">
    <template #default>
      <el-radio-group v-model="page.pid">
        <el-tree ref="treeRef" class="parent-picker" node-key="id" :data="page.tree" :props="{ label: 'title' }" :expand-on-click-node="false">
          <template #default="{ data }">
            <el-row class="node-panel">
              <el-col :span="5">
                <el-radio :label="data.id" :disabled="isExclude(data)">
                  <icon-symbol class="m-r-1" v-if="!!data.icon" :name="data.icon" />
                  <span v-text="data.title"></span>
                </el-radio>
              </el-col>
              <el-col :span="19">
                <div class="node-actions" v-if="!!data.actions">
                  <el-tag v-for="{ id, title, icon } in data.actions" :key="id">
                    <icon-symbol class="m-r-1" v-if="!!icon" :name="icon" />
                    <span v-text="title"></span>
                  </el-tag>
                </div>
              </el-col>
            </el-row>
          </template>
        </el-tree>
      </el-radio-group>
    </template>
    <template #footer>
      <el-button type="primary" @click="save">确定</el-button>
      <el-button @click="close">取消</el-button>
    </template>
  </vxe-modal>
</template>

<style lang="scss" scoped>
.el-radio-group {
  display: initial;
}

.parent-picker {
  border: 1px solid var(--vxe-input-border-color);
  border-radius: var(--vxe-border-radius);
  padding: 2px;

  :deep(.el-tree-node) {
    white-space: unset;
  }

  :deep(.el-tree-node__content) {
    height: auto;
    min-height: var(--el-tree-node-content-height);
  }

  .el-tag {
    margin-right: 0.25rem;
    padding: 0 0.25rem;
  }

  .node-panel {
    align-items: center;
    width: 100%;

    .node-actions {
      margin: 2px 0;
      border: 1px dashed #aaaaaa80;
      padding: 2px;
    }
  }
}
</style>
